package com.lhkj.ct.framework.interceptors;

import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.google.common.collect.ImmutableMap;
import com.lhkj.ct.base.constants.ConfigConstants;
import com.lhkj.ct.base.enums.IamsServiceEnum;
import com.lhkj.ct.base.enums.PatSourceEnum;
import com.lhkj.ct.base.enums.ReturnStatus;
import com.lhkj.ct.base.exception.BusinessException;
import com.lhkj.ct.base.exception.SystemException;
import com.lhkj.ct.base.model.LoginUser;
import com.lhkj.ct.base.model.ro.ActionResult;
import com.lhkj.ct.base.utils.ShiroUtil;
import com.lhkj.ct.base.utils.UrlUtil;
import com.lhkj.ct.base.utils.Validate;
import com.lhkj.ct.base.utils.http.HttpUtils;
import com.lhkj.ct.framework.auth.ro.WxOAuth2UserInfo;
import com.lhkj.ct.framework.auth.service.AuthService;
import com.lhkj.ct.framework.shiro.token.AccessTokenAuthenticationToken;
import com.lhkj.ct.meta.admin.service.SysConfigService;
import com.lhkj.ct.meta.modules.auth.common.enums.IdentType;
import com.lhkj.ct.meta.modules.auth.common.enums.UserType;
import com.lhkj.ct.meta.modules.auth.entity.TblUserIdentity;
import com.lhkj.ct.meta.modules.auth.service.UserIdentityService;
import com.lhkj.ct.meta.modules.patient.mapper.PatientMapper;
import com.lhkj.ct.meta.modules.patient.mapper.TblPatSourceMapper;
import com.lhkj.ct.meta.modules.patient.model.entity.TblPatCardRelation;
import com.lhkj.ct.meta.modules.patient.model.entity.TblPatSource;
import com.lhkj.ct.meta.modules.patient.model.entity.TblPatient;
import com.lhkj.ct.meta.modules.patient.service.PatCardRelationService;
import com.lhkj.ct.meta.modules.psychology.mapper.PsyRecordMapper;
import com.lhkj.ct.meta.modules.psychology.model.entity.TblScalePsyRecord;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * 微信公众号访问拦截器
 */
@Component
@SuppressWarnings("NullableProblems")
public class WxMpInterceptor implements HandlerInterceptor {

    private final Logger log = LoggerFactory.getLogger(WxMpInterceptor.class);

    @Resource
    private UserIdentityService userIdentityService;

    @Resource
    private PsyRecordMapper psyRecordMapper;

    @Resource
    private PatientMapper patientMapper;

    @Resource
    private PatCardRelationService patCardRelationService;

    @Resource
    private AuthService authService;

    @Resource
    private TblPatSourceMapper patSourceMapper;

    @Resource
    private SysConfigService sysConfigService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String code = request.getParameter("code");
        String url = request.getParameter("url");
        log.debug("微信拦截器：code = {}, url = {}, 请求来源：{}", code, url, request.getRequestURI());
        if (StringUtils.isBlank(code) || StringUtils.isBlank(url)) {
            return false;
        }
        String appId = sysConfigService.selectConfigByKey(ConfigConstants.SYS_WECHAT_APPID);
        if (appId.isEmpty()) {
            throw new SystemException("系统未配置默认公众号参数，请先前往参数配置进行配置");
        }
        String jsonResult = HttpUtils.sendGet(IamsServiceEnum.USERINFO_URL.getUrl(), ImmutableMap.of("code", code, "mpId", appId));
        ActionResult<WxOAuth2UserInfo> actionResult = JSONObject.parseObject(jsonResult, new TypeReference<ActionResult<WxOAuth2UserInfo>>() {});
        if (!Objects.equals(actionResult.getCode(), ReturnStatus.SUCCESS.getCode())) {
            throw new BusinessException(actionResult.getCode(), actionResult.getMessage());
        }
        String openId = actionResult.getData().getOpenid();
        String nickName = actionResult.getData().getNickname();
        log.debug("微信公众号openId：{}", openId);
        String allotId = UrlUtil.getParameters(url, "allotId");
        if (StringUtils.isNotBlank(allotId)) {
            return handleScaleAllot(allotId, openId, nickName, url, response);
        }
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

    }

    public boolean handleScaleAllot(String allotId, String openId,String nickName, String url, HttpServletResponse response) throws IOException {
        TblScalePsyRecord psyRecord = psyRecordMapper.selectById(allotId);
        Validate.notNull(psyRecord, "分配记录不存在！");
        TblPatient patient = patientMapper.selectById(psyRecord.getPatId());
        Validate.notNull(patient, "档案不存在！");
        // 查询当前微信号是否绑定患者
        String patientId = patient.getId();
        // 查看当前微信号是否已绑定患者
        TblUserIdentity identity = userIdentityService.getByIdentity(UserType.PLATFORM, IdentType.WXP, openId);
        // 如果未绑定则直接绑定该分配记录的档案
        if (identity == null) {
            // 档案来源
            patSourceMapper.insertOnDuplicate(new TblPatSource(patientId, PatSourceEnum.WX, null));
            // 创建默认就诊卡
            TblPatCardRelation patCardRelation = TblPatCardRelation.builder()
                    .identifier(openId)
                    .isDefault(true)
                    .patId(patient.getId())
                    // fixme 这里未对接医院系统，暂时用身份证
                    .patCardNo(patient.getPatIdentNo())
                    .build();
            patCardRelationService.createDefaultCard(patCardRelation);
            // 增加新的微信绑定
            userIdentityService.save( TblUserIdentity.builder()
                            .userId(patient.getId())
                            .identifier(openId)
                            .nickName(nickName)
                            .userType(UserType.PLATFORM)
                            .identType(IdentType.WXP)
                    .build());
            AccessTokenAuthenticationToken token = new AccessTokenAuthenticationToken(UserType.PLATFORM, openId, IdentType.WXP);
            authService.h5SessionId(token);
        }else{
            // 如果已绑定，则作为就诊卡号绑定
            AccessTokenAuthenticationToken token = new AccessTokenAuthenticationToken(UserType.PLATFORM, openId, IdentType.WXP);
            authService.h5SessionId(token);
            patCardRelationService.bindPatCard(TblPatCardRelation.builder()
                    .identifier(openId)
                    .isDefault(false)
                    .patId(patient.getId())
                    // fixme 这里未对接医院系统，暂时用身份证
                    .patCardNo(patient.getPatIdentNo())
                    .build(), true);
            LoginUser authUserInfo = ShiroUtil.getAuthUserInfo();
            authUserInfo.setUserId(patientId);
            ShiroUtil.setUser(authUserInfo);
        }
        response.sendRedirect(url + "&token=" + ShiroUtil.getSession().getId());
        return true;
    }

}
